package demoMod.invincibleOne.patches;

import basemod.ReflectionHacks;
import com.evacipated.cardcrawl.modthespire.lib.*;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.localization.UIStrings;
import com.megacrit.cardcrawl.neow.NeowEvent;
import com.megacrit.cardcrawl.random.Random;
import com.megacrit.cardcrawl.vfx.InfiniteSpeechBubble;
import demoMod.invincibleOne.InvincibleOneMod;
import demoMod.invincibleOne.characters.InvincibleOne;
import demoMod.invincibleOne.neow.InvincibleReward;
import demoMod.invincibleOne.neow.InvincibleRewardItem;
import javassist.CtBehavior;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class NeowEventPatch {
    @SpirePatch(
            clz = NeowEvent.class,
            method = SpirePatch.CONSTRUCTOR,
            paramtypez = {
                    boolean.class
            }
    )
    public static class PatchConstructor {
        @SpireInsertPatch(locator = Locator.class)
        public static void Insert(NeowEvent neowEvent, boolean isDone) {
            if (AbstractDungeon.player instanceof InvincibleOne) {
                ReflectionHacks.setPrivate(neowEvent, NeowEvent.class, "screenNum", 2580);
            }
        }

        private static final class Locator extends SpireInsertLocator {
            @Override
            public int[] Locate(CtBehavior ctMethodToPatch) throws Exception {
                Matcher finalMatcher = new Matcher.FieldAccessMatcher(AbstractDungeon.class, "topLevelEffects");
                int[] lines = LineFinder.findAllInOrder(ctMethodToPatch, finalMatcher);
                return new int[]{lines[lines.length - 1] - 2};
            }
        }
    }

    @SpirePatch(
            clz = NeowEvent.class,
            method = "update"
    )
    public static class PatchUpdate {
        public static void Postfix(NeowEvent event) {
            PatchButtonEffect.rewards.forEach(InvincibleReward::update);
        }
    }

    @SpirePatch(
            clz = NeowEvent.class,
            method = "buttonEffect"
    )
    public static class PatchButtonEffect {
        private static final float DIALOG_X = 1100.0F * Settings.xScale;
        private static final float DIALOG_Y = AbstractDungeon.floorY + 60.0F * Settings.yScale;
        private static final UIStrings uiStrings = CardCrawlGame.languagePack.getUIString(InvincibleOneMod.makeID("Blessings"));
        public static final List<InvincibleReward> rewards = new ArrayList<>();

        public static SpireReturn<Void> Prefix(NeowEvent neowEvent, int buttonPressed) {
            int screenNum = ReflectionHacks.getPrivate(neowEvent, NeowEvent.class, "screenNum");
            switch (screenNum) {
                case 2580:
                    try {
                        ReflectionHacks.getCachedMethod(NeowEvent.class, "dismissBubble").invoke(neowEvent);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                    NeowEvent.rng = new Random(Settings.seed);
                    boolean miniBlessing = (int) ReflectionHacks.getPrivate(neowEvent, NeowEvent.class, "bossCount") == 0 && !Settings.isTestingNeow;
                    AbstractDungeon.effectList.add(new InfiniteSpeechBubble(DIALOG_X, DIALOG_Y, uiStrings.TEXT[miniBlessing ? 0 : 1]));
                    Arrays.stream(InvincibleRewardItem.values()).forEach(InvincibleRewardItem::reset);
                    rewards.clear();
                    neowEvent.roomEventText.clearRemainingOptions();
                    if (!miniBlessing) {
                        rewards.addAll(InvincibleReward.getRandomReward(NeowEvent.rng, 4));
                        neowEvent.roomEventText.updateDialogOption(0, rewards.get(0).getDescription());
                        neowEvent.roomEventText.addDialogOption(rewards.get(1).getDescription());
                        neowEvent.roomEventText.addDialogOption(rewards.get(2).getDescription());
                        neowEvent.roomEventText.addDialogOption(rewards.get(3).getDescription());
                    } else {
                        rewards.addAll(InvincibleReward.getRandomMiniReward(NeowEvent.rng, 2));
                        neowEvent.roomEventText.updateDialogOption(0, rewards.get(0).getDescription());
                        neowEvent.roomEventText.addDialogOption(rewards.get(1).getDescription());
                    }
                    ReflectionHacks.setPrivate(neowEvent, NeowEvent.class, "screenNum", 2581);
                    return SpireReturn.Return(null);
                case 2581:
                    try {
                        ReflectionHacks.getCachedMethod(NeowEvent.class, "dismissBubble").invoke(neowEvent);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                    neowEvent.roomEventText.clearRemainingOptions();
                    InvincibleReward reward = rewards.get(buttonPressed);
                    reward.activate();
                    AbstractDungeon.effectList.add(new InfiniteSpeechBubble(DIALOG_X, DIALOG_Y, uiStrings.TEXT[reward.getItems().size() > 1 ? 3 : 2]));
                    neowEvent.roomEventText.updateDialogOption(0, NeowEvent.OPTIONS[1]);
                    ReflectionHacks.setPrivate(neowEvent, NeowEvent.class, "screenNum", 99);
                    return SpireReturn.Return(null);
            }
            return SpireReturn.Continue();
        }
    }
}
